Substance Painter shader

Created by miccall (转载请注明出处 miccall.tech)

基于substance painter 2018.2.3

入口 :

substance 的 shader 用的就是普通的 glsl 文件 ,导入直接拖进去就ok 。
但是写法还有有一定的区别 。

我们随便新建一个 glsl :


void shade(V2F inputs) {
  diffuseShadingOutput(vec3(1.0, 0.0, 1.0));
}

这个就是我们的入口函数,直接返回一个值 。

在substance painter 里面,直接设置这个shader就可以看到效果了 。

V2F和unity 差不多 ,就是 vertex 到 fragment 的 结构体 ,只是 substance 不允许我们写 vert shader


struct V2F {
  vec3 normal;               // interpolated normal
  vec3 tangent;              // interpolated tangent
  vec3 bitangent;            // interpolated bitangent
  vec3 position;             // interpolated position
  vec4 color[1];             // interpolated vertex colors (color0)
  vec2 tex_coord;            // interpolated texture coordinates (uv0)
  vec2 multi_tex_coord[8];   // interpolated texture coordinates (uv0-uv7)
};

基本上我们要的东西都有了 。

输出也有一定的规范 ,以前的版本是


return  emissiveColor + albedo * diffuseShading + specularShading 

但是现在 sp 把 几者都分开了 ,我们只能按照通道返回相应的值:


// fragment opacity. default value: 1.0
void alphaOutput(float);


// diffuse lighting contribution. default value: vec3(0.0)
void diffuseShadingOutput(vec3);


// specular lighting contribution. default value: vec3(0.0)
void specularShadingOutput(vec3);

// color emitted by the fragment. default value: vec3(0.0)
void emissiveColorOutput(vec3);

// fragment color. default value: vec3(1.0)
void albedoOutput(vec3);

// subsurface scattering properties, see lib-sss.glsl for details. default value: vec4(0.0)

void sssCoefficientsOutput(vec4);

除了基本的输入输出通道,我们还有其他的一些资源可以使用 :


//:param auto TEXTURE_TAG 
uniform  sampler2D  uniform_tex ;    //纹理本身

//:param auto TEXTURE_TAG_is_set 
uniform  bool  uniform_tex_is_set ;  //一个布尔值,指示纹理是否在文档中

//:param auto TEXTURE_TAG_size 
uniform  vec4  uniform_tex_size ;    //纹理的大小(宽度,高度,1 /宽度,1 /高度)

等等还有很多贴图 ,具体可以参考帮助文档 。

在 substance painter 中 ,//: 后面的不是注释,而是 一种参数配置

这种定制方法使我们可以自定义数据类型


// 定义一个 RGB的 color 默认值为 0 
//: param custom { "default": 0, "label": "Color RGB", "widget": "color" }
uniform vec3 u_color_float3;


// 定义一个 RGBA 的 color 默认值为 1 
//: param custom { "default": 1, "label": "Color RGBA", "widget": "color" }
uniform vec4 u_color_float4;


// 当然,label 还有  Int spinbox, 
// "Int slider", "min": 0, "max": 10  

// 等等 。。。 

除了基本变量 ,substance painter 还给我们定制了一些 function

用的时候直接 import :


lib-alpha.glsl:包含不透明度相关的
lib-bayer.glsl:包含拜耳矩阵
lib-defines.glsl:包含有用的数学常量
lib-emissive.glsl:包含自发光属性
lib-env.glsl:包含与环境贴图相关的帮助程序
lib-normal.glsl:包含与法线相关的(以及高度图生成的法线贴图)
lib-pbr.glsl:包含基于物理的渲染
lib-pom.glsl:包含视差遮挡映射
lib-random.glsl:包含随机实用程序(hammersley序列)
lib-sampler.glsl:包含channel getters
lib-sss.glsl:包含次表面散射
lib-utils.glsl:包含颜色实用程序函数(sRGB转换,色调映射)
lib-vectors.glsl:包含常见的向量

// api 和源码都有 

默认材质 pbr-metal-rough


void shade(V2F inputs)
{
  // Apply parallax occlusion mapping if possible
  vec3 viewTS = worldSpaceToTangentSpace(getEyeVec(inputs.position), inputs);
  inputs.tex_coord += getParallaxOffset(inputs.tex_coord, viewTS);

  // Fetch material parameters, and conversion to the specular/roughness model
  float roughness = getRoughness(roughness_tex, inputs.tex_coord);
  vec3 baseColor = getBaseColor(basecolor_tex, inputs.tex_coord);
  float metallic = getMetallic(metallic_tex, inputs.tex_coord);
  float specularLevel = getSpecularLevel(specularlevel_tex, inputs.tex_coord);
  vec3 diffColor = generateDiffuseColor(baseColor, metallic);
  vec3 specColor = generateSpecularColor(specularLevel, baseColor, metallic);
  // Get detail (ambient occlusion) and global (shadow) occlusion factors
  float occlusion = getAO(inputs.tex_coord) * getShadowFactor();
  float specOcclusion = specularOcclusionCorrection(occlusion, metallic, roughness);

  LocalVectors vectors = computeLocalFrame(inputs);

  // Feed parameters for a physically based BRDF integration
  emissiveColorOutput(pbrComputeEmissive(emissive_tex, inputs.tex_coord));
  albedoOutput(diffColor);
  diffuseShadingOutput(occlusion * envIrradiance(vectors.normal));
  specularShadingOutput(specOcclusion * pbrComputeSpecular(vectors, specColor, roughness));
  sssCoefficientsOutput(getSSSCoefficients(inputs.tex_coord));
}

更改我们的shader ,支持各向异性 头发 :

我们只需更改高光部分就ok :


  specularShadingOutput(specOcclusion * HairSpecular(vectors, specColor, roughness));

这个方法是我们自定义的方法 :


vec3 ShiftTangent ( vec3 T, vec3 N)
{
    return normalize(T + _shift * N);
}

vec3 HairSpecular(LocalVectors vectors, vec3 specColor, float roughness)
{
     vec3 radiance = vec3(0.0);
      float ndv = dot(vectors.eye, vectors.normal);
    vec3 T = ShiftTangent(vectors.bitangent,vectors.normal);
    vec3 H = normalize(lightDirection + vectors.eye);
    float dotTH = dot(T, H);
    float sinTH = sqrt(1 - dotTH * dotTH);
    float dirAtten = smoothstep(-1, 0, dotTH);
    radiance = vec3(dirAtten * pow(sinTH, 100.0)) * specColor ;
     return radiance;
}

default :

custom :

这是一个极其简化的公式 ,到时候会研究一下substance painter 的BRDF 公式 ,他似乎对每一项都进行了循环采样,使得效果不是unity和unreal 可以比拟的。
所以很多美术吐槽在substance里面效果很好,为什么到了引擎里面折扣这么大 。